﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.Xml;
using Ashwani.Cryptography.Symmetric;
using Ashwani.Cryptography.Signature;
using Ashwani.Cryptography.Hashing;

namespace Ashwani.Cryptography
{
    public class Cryptographer
    {

        private Dictionary<string, ISymmetricCryptoProvider> _symmetricCryptoProviderList = new Dictionary<string, ISymmetricCryptoProvider>();
        private Dictionary<string, ISignatureProvider> _signatureProviderList = new Dictionary<string, ISignatureProvider>();
        private Dictionary<string, IHashProvider> _hashProviderList = new Dictionary<string, IHashProvider>();

        private ISymmetricCryptoProvider _defaultSymmetricCryptoProvider;
        private ISignatureProvider _defaultSignatureProvider;
        private IHashProvider _defaultHashProvider;


        public void AddSymmetricProvider(string key, ISymmetricCryptoProvider provider, bool isDefault)
        {
            _symmetricCryptoProviderList.Add(key, provider);
            if (isDefault || _symmetricCryptoProviderList.Count == 1)
            {
                _defaultSymmetricCryptoProvider = provider;
            }
        }
        public void AddSignatureProvider(string key, ISignatureProvider provider, bool isDefault)
        {
            _signatureProviderList.Add(key, provider);
            if (isDefault || _signatureProviderList.Count == 1)
            {
                _defaultSignatureProvider = provider;
            }
        }
        public void AddHashProvider(string key, IHashProvider provider, bool isDefault)
        {
            _hashProviderList.Add(key, provider);
            if (isDefault || _hashProviderList.Count == 1)
            {
                _defaultHashProvider = provider;
            }
        }


        #region Symmetric Encryption Methods
        public string EncryptSymmetric(string plaintext)
        {
            return EncryptSymmetric(plaintext, string.Empty);
        }
        public string EncryptSymmetric(string plaintext, string providerKey)
        {
            if (string.IsNullOrEmpty(plaintext)) throw new ArgumentException("", "plaintext");
            byte[] plainTextBytes = UnicodeEncoding.Unicode.GetBytes(plaintext);
            byte[] cipherTextBytes = this.GetSymmetricCryptoProvider(providerKey).Encrypt(plainTextBytes);

            //CryptographyUtility.GetRandomBytes(plainTextBytes);
            return Convert.ToBase64String(cipherTextBytes);
        }

        public string DecryptSymmetric(string ciphertextBase64)
        {
            return DecryptSymmetric(ciphertextBase64, string.Empty);
        }
        public string DecryptSymmetric(string ciphertextBase64, string providerKey)
        {
            if (string.IsNullOrEmpty(ciphertextBase64)) throw new ArgumentException("", "ciphertextBase64");

            byte[] cipherTextBytes = Convert.FromBase64String(ciphertextBase64);
            byte[] decryptedBytes = this.GetSymmetricCryptoProvider(providerKey).Decrypt(cipherTextBytes);
            string decryptedString = UnicodeEncoding.Unicode.GetString(decryptedBytes);
            //CryptographyUtility.GetRandomBytes(decryptedBytes);

            return decryptedString;
        }


        public void EncryptXml(XmlDocument Doc, string ElementName)
        {
            EncryptXml(Doc, ElementName, string.Empty);
        }
        public void EncryptXml(XmlDocument Doc, string ElementName, string providerKey)
        {
            this.GetSymmetricCryptoProvider(providerKey).EncryptXml(Doc, ElementName);
        }

        public void DecryptXml(XmlDocument Doc)
        {
            DecryptXml(Doc, string.Empty);
        }
        public void DecryptXml(XmlDocument Doc, string providerKey)
        {
            this.GetSymmetricCryptoProvider(providerKey).DecryptXml(Doc);
        }


        private ISymmetricCryptoProvider GetSymmetricCryptoProvider(string providerKey)
        {
            ISymmetricCryptoProvider provider = null;
            if (string.IsNullOrEmpty(providerKey))
            {
                provider = this._defaultSymmetricCryptoProvider;
            }
            else
            {
                provider = _symmetricCryptoProviderList[providerKey];
            }
            return provider;
        }

        #endregion

        #region Hashing Methods
        public string ComputeHash(string plaintext)
        {
            return ComputeHash(plaintext, string.Empty);
        }
        public string ComputeHash(string plaintext, string providerKey)
        {
            byte[] valueToHash = UnicodeEncoding.Unicode.GetBytes(plaintext);
            byte[] hashedValue = GetHashProvider(providerKey).ComputeHash(valueToHash);
            return Convert.ToBase64String(hashedValue);
        }

        public bool CompareHash(string plaintext, string hashedtextBase64)
        {
            return CompareHash(plaintext, hashedtextBase64, string.Empty);
        }
        public bool CompareHash(string plaintext, string hashedtextBase64, string providerKey)
        {
            byte[] valueToHash = UnicodeEncoding.Unicode.GetBytes(plaintext);
            byte[] hashedtext = Convert.FromBase64String(hashedtextBase64);
            bool matched = GetHashProvider(providerKey).CompareHash(valueToHash, hashedtext);
            return matched;
        }

        private IHashProvider GetHashProvider(string providerKey)
        {
            IHashProvider provider = null;
            if (string.IsNullOrEmpty(providerKey))
            {
                provider = this._defaultHashProvider;
            }
            else
            {
                provider = _hashProviderList[providerKey];
            }
            return provider;
        }
        #endregion

        #region Signature Methods
        public string CreateSignature(string plaintext)
        {
            return CreateSignature(plaintext, string.Empty);
        }
        public string CreateSignature(string plaintext, string providerKey)
        {
            byte[] valueToHash = UnicodeEncoding.Unicode.GetBytes(plaintext);
            byte[] hashedValue = this.GetSignatureProvider(providerKey).CreateSignature(valueToHash);
            return Convert.ToBase64String(hashedValue);

        }

        public bool CompareSignature(string plaintext, string hashedtextBase64)
        {
            return CompareSignature(plaintext, hashedtextBase64, string.Empty);
        }
        public bool CompareSignature(string plaintext, string hashedtextBase64, string providerKey)
        {
            byte[] valueToHash = UnicodeEncoding.Unicode.GetBytes(plaintext);
            byte[] hashedtext = Convert.FromBase64String(hashedtextBase64);
            bool matched = this.GetSignatureProvider(providerKey).CompareSignature(valueToHash, hashedtext);
            return matched;
        }

        private ISignatureProvider GetSignatureProvider(string providerKey)
        {
            ISignatureProvider provider = null;
            if (string.IsNullOrEmpty(providerKey))
            {
                provider = this._defaultSignatureProvider;
            }
            else
            {
                provider = _signatureProviderList[providerKey];
            }
            return provider;
        }
        #endregion
    }
}
